package de.fuberlin.processing.who.cancer.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.Vector;


public class ApplicationArgumentProcessor {

	private String[] args;
	
	private HashMap<String, String> arguments = new HashMap<String, String>();
	
	private Vector<String> validArgumentKeywords = new Vector<String>();
	
	
	public ApplicationArgumentProcessor( String[] args, String ...argumentKeywords) throws InvalidArgumentException {
		super();
		this.args = args;
		for ( String argument : argumentKeywords) {			
			if ( !validArgumentKeywords.contains( argument))
			  validArgumentKeywords.add( argument);	
		}
		scanAndAnalyseArgs();
	}
		
	
	/**
	 * Untersucht die Argumentliste; und fügt diese ggf. der hashmap zu
	 * @throws InvalidArgumentException 
	 */
	private void scanAndAnalyseArgs() throws InvalidArgumentException {		
		for ( String argument : args) {
			String[] keyValues = argument.split( "=");			
			analyseAndAddToListIfValid( keyValues);
		}
	}
	
	
	/**
	 * Durchsucht eine Datei nach möglichen Parametern. In der Datei sollte ein 
	 * Schlüssel-Wert-Paar (Argument mit Wert) pro Zeile abgelegt sein. 
	 * @param fileWithArguments
	 * @throws IOException
	 * @throws InvalidArgumentException 
	 */
	private void scanAndAnalyseFile( File fileWithArguments) throws IOException, InvalidArgumentException {
		BufferedReader reader = new BufferedReader( 
				new InputStreamReader( 
						new FileInputStream( fileWithArguments)));

		String readedLine;
		while ( ( readedLine = reader.readLine()) != null) {
			String[] keyValues = readedLine.split( "=");			
			analyseAndAddToListIfValid( keyValues);
		}		
	}

	
	/**
	 * Prüft ein Schlüssel-Wert-Paar auf gültigkeit. Sofern beide valide Werte haben und der Schlüssel 
	 * in validArgumentKeywords bekannt ist, wird das Wert-Paar in der Hashmap abgelegt, anderenfalls 
	 * eine Exception geworfen.   
	 * @param keyValuePair
	 * @throws InvalidArgumentException
	 */
	private void analyseAndAddToListIfValid( String[] keyValuePair) throws InvalidArgumentException {	
		if ( keyValuePair.length > 1) {			
			String key = keyValuePair[0]; 
			String value = keyValuePair[1];
			if ( key.equals( "argfile"))
				try {
					scanAndAnalyseFile( new File( value));
				} catch ( IOException e) {
					throw new InvalidArgumentException( String.format( "IOError while reading from argument file %s.", value));
				}
			else
			if ( validArgumentKeywords.contains( key))
				arguments.put( key, value);
		} else {
			if ( keyValuePair.length == 0)
				throw new InvalidArgumentException( "Invalid Argument"); else
				throw new InvalidArgumentException( String.format( "Unknown argument %s.", keyValuePair[0]));
		}
	}
	
	
	/**
	 * Ist ein solches Argument bekannt? 
	 * @param argument
	 * @return
	 */
	public boolean hasArgument( String argument) {
		return arguments.containsKey( argument);
	}
	
	
	/**
	 * Liefert den Wert zu einem Schlüssel, falls dieser existiert.
	 * Anderenfalls wird eine Exception geworfen 
	 * @param argument
	 * @return
	 */
	public String getValueOfArgument( String argument) throws NoSuchElementException {
		if ( hasArgument( argument))
		  return arguments.get( argument); else
		  throw new NoSuchElementException();   	
	}
	
	
	
	@Override
	public String toString() {
		String str = "";
		for ( String argumentKey : arguments.keySet()) {
			str += String.format( "%s=%s\n", argumentKey, arguments.get( argumentKey));
		}
		return str;
	}

	
	public static void main( String[] args) {
		ApplicationArgumentProcessor appargs;
		try {
			appargs = new ApplicationArgumentProcessor( args, "hostname", "master", "workers");
			System.out.println( appargs);
		} catch ( InvalidArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
	}
	
	

}
